#include <string.h>

#include "s_srp_database.h"

#include <sqlite3.h>

namespace dhd
{
namespace server
{
   // SQLite isn't particularly thread-friendly so we'll use an RAII mutex to
   // serialize all use of the API

   SRPDatabase::SRPDatabase( const std::string & sqlite_db_filename )
   {
       const char * q_str = "SELECT s,v FROM users WHERE username = ?";
       
       if( sqlite3_open( sqlite_db_filename.c_str(), &conn ) != SQLITE_OK )
       { 
           DatabaseException e( sqlite3_errmsg(conn) );
           sqlite3_close(conn);
           throw e;
       }
       
       if( sqlite3_prepare_v2( conn, q_str, -1, &query, NULL ) != SQLITE_OK )
       {
           DatabaseException e( sqlite3_errmsg(conn) );
           sqlite3_close(conn);
           throw e;
       }
   }
   
   
   SRPDatabase::~SRPDatabase()
   {
       boost::mutex::scoped_lock guard(db_mutex);
       
       sqlite3_finalize(query);
       sqlite3_close(conn);
   }
   
   
   SRPVerifier * SRPDatabase::get_verifier( const std::string & in_username, const std::string & in_bytes_A,
                                            std::string & out_bytes_s, std::string & out_bytes_B )
   {
       out_bytes_s.clear();
       out_bytes_B.clear();
       
       boost::mutex::scoped_lock guard(db_mutex);
       
       sqlite3_reset(query);
       
       if( sqlite3_bind_text(query, 1, in_username.c_str(), -1, SQLITE_STATIC) != SQLITE_OK )
           return 0;
       
       if ( sqlite3_step(query) != SQLITE_ROW )
           return 0;
       
       int len_B;
       const unsigned char *s, *v, *bytes_B;
       
       s = (const unsigned char *)sqlite3_column_blob(query, 0);
       v = (const unsigned char *)sqlite3_column_blob(query, 1);
       
       out_bytes_s.assign( (const char *)s, sqlite3_column_bytes(query, 0) );
       
       
       SRPVerifier * ver = srp_verifier_new( in_username.c_str(), 
                                             s, sqlite3_column_bytes(query, 0),
                                             v, sqlite3_column_bytes(query, 1),
                                             (const unsigned char *)in_bytes_A.data(), in_bytes_A.length(),
                                             &bytes_B, &len_B );
       if ( bytes_B )
           out_bytes_B.assign( (const char *)&bytes_B, len_B );
       else
       {
           // SRP-6a safety check failed. 
           srp_verifier_delete( ver );
           ver = 0;
       }
       
       return ver;
   }
   
   
}//end namespace server
}//end namespace dhd



